#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>

#define SHOW_HEX_LINE_LEN (16)
#define SHOW_HEX_HALF_LEN (SHOW_HEX_LINE_LEN / 2)

int __convert_hexchar_to_byte(unsigned char hex, unsigned char *byte)
{
    if ((hex >= '0') && (hex <= '9'))
    {
        hex -= '0';
    }
    else if ((hex >= 'a') && (hex <= 'f'))
    {
        hex = hex - 'a' + 0x0A;
    }
    else if ((hex >= 'A') && (hex <= 'F'))
    {
        hex = hex - 'A' + 0x0A;
    }
    else
    {
        return -EINVAL;
    }

    *byte = hex;
    return 0;
}

ssize_t convert_hexstr_to_byte(const char *hex_str, unsigned char *byte)
{
    int ret = 0;
    size_t len = strlen(hex_str);
    size_t idx_str = 0;
    size_t idx_byte = 0;
    unsigned char h, l;

    if (len % 2 != 0)
    {
        h = '0';
        l = hex_str[0];
        idx_str = -1;
        goto l_convert;
    }
    for (idx_byte = 0; idx_str < len; idx_str += 2, idx_byte++)
    {
        h = hex_str[idx_str];
        l = hex_str[idx_str + 1];

    l_convert:
        if ((ret = __convert_hexchar_to_byte(h, &h)))
        {
            return ret;
        }
        if ((ret = __convert_hexchar_to_byte(l, &l)))
        {
            return ret;
        }

        byte[idx_byte] = h << 4 | l;
    }

    return idx_byte;
}

static void __show_ascii(const uint8_t *ascii, uint8_t len)
{
    uint8_t idx_each_asc = 0;

    int16_t right = SHOW_HEX_LINE_LEN - len;
    // 不足一行的补空格
    if (right > 0)
    {
        // 每个字符打印两位16进制数，再加上一个空格，所以空格数量是不足字符数量的三倍
        uint8_t space = right * 3;
        // 不足一行的一半，要多补一个空格，因为一行的中间是两个空格
        if (right > SHOW_HEX_HALF_LEN)
        {
            space++;
        }
        for (idx_each_asc = 0; idx_each_asc < space; idx_each_asc++)
        {
            printf(" ");
        }
    }
    printf(" |");
    for (idx_each_asc = 0; idx_each_asc < len; idx_each_asc++)
    {
        if ((ascii[idx_each_asc] >= 0x20) && (ascii[idx_each_asc] <= 0x7E))
        {
            printf("%c", ascii[idx_each_asc]);
        }
        else
        {
            printf(".");
        }
    }
    printf("|");
}

void show_hex(const char *tag, const void *data, size_t len)
{
    size_t i;
    uint8_t ascii[SHOW_HEX_LINE_LEN];
    uint8_t idx_asc = 0;

    if (tag)
    {
        printf("%s:\n", tag);
    }
    if (!data)
    {
        printf("The data is NULL!");
        return;
    }
    const uint8_t *buf = (const uint8_t *)data;
    for (i = 0; i < len; i++)
    {
        // Show offset address
        if ((i & (SHOW_HEX_LINE_LEN - 1)) == 0)
        {
            printf("%08X  ", (unsigned int)i);
        }

        ascii[idx_asc++] = buf[i];
        printf("%02X ", (buf[i] & 0xFF));

        // 计算余数 a % 2^n == a & (2^n-1)
        if ((((i + 1) & (SHOW_HEX_HALF_LEN - 1)) == 0) // 半行补一个空格
            && (((i + 1) & (SHOW_HEX_LINE_LEN - 1)) != 0))
        {
            printf(" ");
        }
        else if (((i + 1) & (SHOW_HEX_LINE_LEN - 1)) == 0) // 全行打印 ascii 和换行符
        {
            __show_ascii(ascii, idx_asc);
            printf("\n");
        }

        if (idx_asc >= SHOW_HEX_LINE_LEN)
        {
            idx_asc = 0;
        }
    }
    if ((len & (SHOW_HEX_LINE_LEN - 1)))
    {
        __show_ascii(ascii, idx_asc);
        printf("\n");
    }
    printf("%08X\n", (unsigned int)i);
}

void dataToHexStr(const void *data, size_t dataLen, char *hexBuf)
{
    size_t i, outLen = dataLen * 2 + 1;
    const char *buf = (const char *) data;
    uint8_t h = 0, l = 0;

    if (!data)
    {
        return;
    }

    for (i = 0; i < dataLen; i++)
    {
        h = (buf[i] >> 4) & 0x0F;
        l = buf[i] & 0x0F;
        if (h < 10)
        {
            hexBuf[i*2] = h + 0x30;
        }
        else
        {
            hexBuf[i*2] = h - 10 + 0x41;
        }
        if (l < 10)
        {
            hexBuf[i*2+1] = l + 0x30;
        }
        else
        {
            hexBuf[i*2+1] = l - 10 + 0x41;
        }
    }

    hexBuf[outLen] = 0x00;
}

void strToHexStr(const char *str, char *hexBuf)
{
    dataToHexStr(str, strlen(str), hexBuf);
}

#if 0

int main (int argc, char *argv[])
{
    const char *str = "A245AAD94E3E4E49B29283DD7593CA29";
    printf("%s\n", str);
    unsigned char buf[32] = { 0 };
    ssize_t len = convert_hexstr_to_byte(str, buf);
    printf("len=%lld\n", (long long)len);
    if (len < 0)
    {
        fprintf(stderr, "ERROR: %s\n", strerror(len));
        return 1;
    }
    show_hex("str", buf, len);

    const char *str1 = "245AAD94E3E4E49B29283DD7593CA29ABCDEF";
    printf("%s\n", str1);
    bzero(buf, 32);
    len = convert_hexstr_to_byte(str1, buf);
    printf("len=%lld\n", (long long)len);
    if (len < 0)
    {
        fprintf(stderr, "ERROR: %s\n", strerror(len));
        return 1;
    }
    show_hex("str1", buf, len);

    char hexBuf[75] = { 0x00 };
    strToHexStr(str1, hexBuf);
    printf("hexBuf=%s\n", hexBuf);
    show_hex("hexBuf", hexBuf, sizeof(hexBuf));

    return 0;
}

#endif

